﻿//Copyright (c) 2010, Andreas Grünwald
//All rights reserved.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;

namespace yaTDL.Core.MVVM
{
    public abstract class TaskListViewModelBase : NotifyObject
    {
        #region Fields

        protected RelayCommand _addTaskCommand;
        protected RelayCommand _editTaskCommand;
        protected RelayCommand _deleteTaskCommand;
        protected RelayCommand _deleteHistoryCommand;
        protected RelayCommand _sortAllItemsCommand;
        protected RelayCommand _sortPendingItemsCommand;
        protected RelayCommand _sortCompletedItemsCommand;
        protected RelayCommand _showDetailsPaneCommand;
        protected RelayCommand _closeDetailsPaneCommand;

        protected SortableObservableCollection<Task> _pendingItems = new SortableObservableCollection<Task>();
        protected SortableObservableCollection<Task> _completedItems = new SortableObservableCollection<Task>();
        protected SortableObservableCollection<Task> _allItems = new SortableObservableCollection<Task>();
        protected Task _selectedTask;

        protected SortBy _allItemsSort = SortBy.Date;
        protected SortBy _pendingItemsSort = SortBy.Date;
        protected SortBy _completedItemsSort = SortBy.LastEdited;

        protected string _listHeader;


        protected string _sortAllItemsButtonText;
        protected string _sortPendingItemsButtonText;
        protected string _sortCompletedItemsButtonText;

        protected Visibility _detailsPaneVisibility = Visibility.Hidden;

        bool _allItemsViewIsVisible;
        bool _pendingItemsViewIsVisible;
        bool _completedItemsViewIsVisible;

        bool currentlySorting = false;  //indicates wheter one or mote task-collection is currently being sorted

        #endregion

        #region Properties

        /// <summary>
        /// Adds a new Task to the list.
        /// </summary>
        public ICommand AddTaskCommand
        {
            get
            {
                if (_addTaskCommand == null)
                {
                    _addTaskCommand = new RelayCommand(p => this.addTaskCommandExecute(p), p => this.addTaskCommandCanExecute(p));
                }
                return _addTaskCommand;
            }
        }

        /// <summary>
        /// Deletes the currently selected Task.
        /// </summary>
        public ICommand DeleteTaskCommand
        {
            get
            {
                if (_deleteTaskCommand == null)
                {
                    _deleteTaskCommand = new RelayCommand(p => this.deleteTaskCommandExecute(p), p => this.deleteTaskCommandCanExecute(p));
                }
                return _deleteTaskCommand;
            }
        }

        /// <summary>
        /// Deletes all completed Tasks in the task-list.
        /// </summary>
        public ICommand DeleteHistoryCommand
        {
            get
            {
                if (_deleteHistoryCommand == null)
                {
                    _deleteHistoryCommand = new RelayCommand(p => this.deleteHistoryCommandExecute(p), p => this.deleteHistoryCommandCanExecute(p));
                }
                return _deleteHistoryCommand;
            }
        }

        /// <summary>
        /// Sorts AllItems (cycles through the different values of SortBy).
        /// </summary>
        public ICommand SortAllItemsCommand
        {
            get
            {
                if (_sortAllItemsCommand == null)
                {
                    _sortAllItemsCommand = new RelayCommand(p => this.sortAllItemsCommmandExecute(p), p => this.sortAllItemsCommandCanExecute(p));
                }
                return _sortAllItemsCommand;
            }
        }

        /// <summary>
        /// Sorts PendingItems (cycles through the different values of SortBy).
        /// </summary>
        public ICommand SortPendingItemsCommand
        {
            get
            {
                if (_sortPendingItemsCommand == null)
                {
                    _sortPendingItemsCommand = new RelayCommand(p => this.sortPendingItemsCommandExecute(p), p => this.sortPendingItemsCommandCanExecute(p));
                }
                return _sortPendingItemsCommand;
            }
        }

        /// <summary>
        /// Sorts CompletedItems (cycles through the different values of SortBy).
        /// </summary>
        public ICommand SortCompletedItemsCommand
        {
            get
            {
                if (_sortCompletedItemsCommand == null)
                {
                    _sortCompletedItemsCommand = new RelayCommand(p => this.sortCompletedItemsCommandExecute(p), p => this.sortCompletedItemsCommandCanExecute(p));
                }
                return _sortCompletedItemsCommand;
            }
        }

        /// <summary>
        /// Shows the details-pane.
        /// </summary>
        public ICommand ShowDetailsPaneCommand
        {
            get
            {
                if (_showDetailsPaneCommand == null)
                {
                    _showDetailsPaneCommand = new RelayCommand(p => this.showDetailsPaneCommandExecute(p));
                }
                return _showDetailsPaneCommand;
            }

        }

        /// <summary>
        /// Hides the details-pane.
        /// </summary>
        public ICommand CloseDetailsPaneCommand
        {
            get
            {
                if (_closeDetailsPaneCommand == null)
                {
                    _closeDetailsPaneCommand = new RelayCommand(p => this.closeDetailsPaneCommandExecute(p));
                }
                return _closeDetailsPaneCommand;
            }
        }

        /// <summary>
        /// All uncompleted Tasks of the task-list.
        /// </summary>
        public SortableObservableCollection<Task> PendingItems
        {
            get { return _pendingItems; }
            set 
            {
                if (value != _pendingItems)
                {
                    _pendingItems = value;
                    RaisePropertyChanged("PendingItems");
                }
            }
        }

        /// <summary>
        /// All completed Tasks of the task-list.
        /// </summary>
        public SortableObservableCollection<Task> CompletedItems
        {
            get { return _completedItems; }
            set 
            {
                if (value != _completedItems)
                {                        
                    _completedItems = value;
                    RaisePropertyChanged("CompletedItems");
                }
            }
        }

        /// <summary>
        /// All Tasks of the task-list.
        /// </summary>
        public SortableObservableCollection<Task> AllItems
        {
            get { return _allItems; }
            set 
            {
                if (value != _allItems)
                {
                    _allItems = value;
                    RaisePropertyChanged("AllItems");
                }
            }
        }

        /// <summary>
        /// The currently selected Task.
        /// </summary>
        public Task SelectedTask
        {
            get { return _selectedTask; }
            set
            {
                if (value != _selectedTask)
                {
                    _selectedTask = value;

                    //hide/show the DetailsPane based on the value of SelectedTask
                    if (!currentlySorting)
                        DetailsPaneVisibility = _selectedTask == null ? Visibility.Hidden : Visibility.Visible;


                    //Switch to the right 'section' (all/pending/completed) to make sure the now selected Task is visible to the user.
                    if (!AllItemsViewIsVisible && _selectedTask != null)
                    {
                        switch (_selectedTask.Completed)
                        {
                            case true:
                                CompletedItemsViewIsVisible = true;
                                break;
                            case false:
                                PendingItemsViewIsVisible = true;
                                break;
                        }
                    }

                    RaisePropertyChanged("SelectedTask");
                }
            }
        }

        /// <summary>
        /// Indicates how AllItems is currently sorted.
        /// </summary>
        public SortBy AllItemsSort
        {
            get { return _allItemsSort; }
            set
            {
                if (value != _allItemsSort)
                {
                    _allItemsSort = value;
                    RaisePropertyChanged("AllItemsSort");
                }
            }
        }

        /// <summary>
        /// Indicates how PendingItems is currently sorted.
        /// </summary>
        public SortBy PendingItemsSort
        {
            get { return _pendingItemsSort; }
            set
            {
                if (value != _pendingItemsSort)
                {
                    _pendingItemsSort = value;
                    RaisePropertyChanged("PendingItemsSort");
                }
            }
        }

        /// <summary>
        /// Indicates how CompletedItems is currently sorted.
        /// </summary>
        public SortBy CompletedItemsSort
        {
            get { return _completedItemsSort; }
            set
            {
                if (value != _completedItemsSort)
                {
                    _completedItemsSort = value;
                    RaisePropertyChanged("CompletedItemsSort");
                }
            }
        }

        /// <summary>
        /// The header of the task-list decribing what's currently displayed.
        /// </summary>
        public string ListHeader
        {
            get { return _listHeader.ToUpper(); }
            set
            {
                if (value != _listHeader)
                {
                    _listHeader = value;
                    RaisePropertyChanged("ListHeader");
                }
            }
        }

        /// <summary>
        /// The Text to be displayed on the button that executed the SortAllItemsCommand.
        /// </summary>
        public string SortAllItemsButtonText
        {
            get { return _sortAllItemsButtonText; }
            set
            {
                if (value != _sortAllItemsButtonText)
                {
                    _sortAllItemsButtonText = value;
                    RaisePropertyChanged("SortAllItemsButtontext");
                }
            }
        }

        /// <summary>
        /// The Text to be displayed on the button that executed the SortPendingItemsCommand.
        /// </summary>
        public string SortPendingItemsButtonText
        {
            get { return _sortPendingItemsButtonText; }
            set
            {
                if (value != _sortPendingItemsButtonText)
                {
                    _sortPendingItemsButtonText = value;
                    RaisePropertyChanged("SortPendingItemsButtonText");
                }
            }
        }

        /// <summary>
        /// The Text to be displayed on the button that executed the SortCompletedItemsCommand.
        /// </summary>
        public string SortCompletedItemsButtonText
        {
            get { return _sortCompletedItemsButtonText; }
            set
            {
                if (value != _sortCompletedItemsButtonText)
                {
                    _sortCompletedItemsButtonText = value;
                    RaisePropertyChanged("SortCompletedItemsButtonText");
                }
            }
        }

        /// <summary>
        /// The Visibility of the details-pane.
        /// </summary>
        public Visibility DetailsPaneVisibility
        {
            get { return _detailsPaneVisibility; }
            set
            {
                if (value != _detailsPaneVisibility)
                {
                    _detailsPaneVisibility = value;
                    RaisePropertyChanged("DetailsPaneVisibility");
                }
            }
        }

        /// <summary>
        /// Indicated if the View displaying 'AllItems' is currently visble to the user.
        /// </summary>
        public bool AllItemsViewIsVisible
        {
            get { return _allItemsViewIsVisible; }
            set 
            {
                if (value != _allItemsViewIsVisible)
                {
                    _allItemsViewIsVisible = value;
                    RaisePropertyChanged("AllItemsViewIsVisible");
                }
            }
        }

        /// <summary>
        /// Indicated if the View displaying 'PendingItems' is currently visble to the user.
        /// </summary>
        public bool PendingItemsViewIsVisible
        {
            get { return _pendingItemsViewIsVisible; }
            set
            {
                if (value != _pendingItemsViewIsVisible)
                {
                    _pendingItemsViewIsVisible = value;
                    RaisePropertyChanged("PendingItemsViewIsVisible");
                }
            }
        }

        /// <summary>
        /// Indicated if the View displaying 'CompletedItems' is currently visble to the user.
        /// </summary>
        public bool CompletedItemsViewIsVisible
        {
            get { return _completedItemsViewIsVisible; }
            set
            {
                if (value != _completedItemsViewIsVisible)
                {
                    _completedItemsViewIsVisible = value;
                    RaisePropertyChanged("CompletedItemsViewIsVisible");
                }
            }
        }

        #endregion



        #region Constructor and private/protected Methods

        /// <summary>
        /// Initializes a new instance os TaskListViewModelBase.
        /// </summary>
        public TaskListViewModelBase()
        {

            PendingItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(updateAllItemsCollection);
            CompletedItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(updateAllItemsCollection);

            //subscribe to task-events in TaskStore
            TaskStore.TaskAdded += new EventHandler<TaskEventArgs>(TaskStore_TaskAdded_threadsafe);
            TaskStore.TaskDeleted += new EventHandler<TaskEventArgs>(TaskStore_TaskDeleted);
            TaskStore.TaskPropertyChanged += new EventHandler<PropertyChangedEventArgs>(TaskStore_TaskPropertyChanged_threadsafe);  

            //initially sort tasks
            sortAllTaskCollections();


            //subscribe to own PropertyChangedEvent
            this.PropertyChanged += new PropertyChangedEventHandler(TaskListViewModelBase_PropertyChanged);

            PendingItemsViewIsVisible = true;
        }

        

        /// <summary>
        /// EventHandler for the TaskStore.TaskAdded event and calls TaskStore_TaskAdded. If the executing thread is not the UI-thread the method call will be invoked in the UI-thread.
        /// </summary>
        /// <param name="sender">The event's sender.</param>
        /// <param name="e">EventArgs for the event.</param>
        protected virtual void TaskStore_TaskAdded_threadsafe(object sender, TaskEventArgs e)
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { TaskStore_TaskAdded_threadsafe(sender, e); }));
                return;
            }

            TaskStore_TaskAdded(sender, e);

        }

        /// <summary>
        /// Method that will be called when the TaskStore.TaskAdded event is raised. 
        /// Inheriting classes need to implement this and make sure to update their data correctly.
        /// You should not call this method directly as it is not thread-safe. Call TaskStore_TaskAdded_threadsafe() instead.
        /// </summary>
        /// <param name="sender">The event's sender.</param>
        /// <param name="e">EventArgs for the event.</param>
        protected abstract void TaskStore_TaskAdded(object sender, TaskEventArgs e);

        /// <summary>
        /// EventHandler for the TaskStore.TaskDeleted event
        /// If necessary, inheriting should override this and make sure to update their data correctly.
        /// When overriding, you need to make sure, the method is threadsafe if you manipulate items that are used in the UI thread.
        /// </summary>
        /// <param name="sender">The event's sender.</param>
        /// <param name="e">EventArgs for the event.</param>
        protected virtual void TaskStore_TaskDeleted(object sender, TaskEventArgs e)
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { TaskStore_TaskDeleted(sender, e); }));
                return;
            }            
            

            ObservableCollection<Task> tasks = e.Task.Completed ? CompletedItems : PendingItems;

            if (tasks.Contains(e.Task))
                tasks.Remove(e.Task);
        }


        /// <summary>
        /// EventHandler for the TaskStore.TaskPropertiesUpdated event and calls TaskStore_TaskPropertiesUpdated. If the executing thread is not the UI-thread the method call will be invoked in the UI-thread.
        /// </summary>
        /// <param name="sender">The event's sender.</param>
        /// <param name="e">EventArgs for the event.</param>
        protected virtual void TaskStore_TaskPropertyChanged_threadsafe(object sender, PropertyChangedEventArgs e)
        {
            if (Application.Current.Dispatcher.CheckAccess())
            {
                TaskStore_TaskPropertyChanged(sender, e);
            }
            else
            {
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { TaskStore_TaskPropertyChanged(sender, e); }));
            }

        }

        /// <summary>
        /// Method that will be called when the TaskStore.TaskPropertiesUpdated event is raised. 
        /// Inheriting classes need to implement this and make sure to update their data correctly.
        /// You should not call this method directly as it is not thread-safe. Call TaskStore_TaskPropertiesUpdated_threadsafe() instead.
        /// </summary>
        /// <param name="sender">The event's sender.</param>
        /// <param name="e">EventArgs for the event.</param>        
        protected abstract void TaskStore_TaskPropertyChanged(object sender, PropertyChangedEventArgs e);

        /// <summary>
        /// Updates AllItems when CompletedItems and/or PendingItems has changed.
        /// When overriding, you need to make sure, the method is threadsafe if you manipulate items that are used in the UI thread.
        /// </summary>
        /// <param name="sender">The event's sender.</param>
        /// <param name="e">EventArgs for the event.</param>      
        protected virtual void updateAllItemsCollection(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (!Application.Current.Dispatcher.CheckAccess())
            {
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { updateAllItemsCollection(sender, e); }));
                
                return;
            }

            AllItems = new SortableObservableCollection<Task>(PendingItems.Union(CompletedItems));

            SortAllItemsButtonText = String.Format("{0} Tasks by {1}", AllItems.Count, AllItemsSort.ToString());
            SortPendingItemsButtonText = String.Format("{0} Tasks by {1}", PendingItems.Count, PendingItemsSort.ToString());
            SortCompletedItemsButtonText = String.Format("{0} Tasks by {1}", CompletedItems.Count, CompletedItemsSort.ToString());
        }

  

        private void TaskListViewModelBase_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            //The task-list will not be sorted, while the details-pane is visible, so it may need to be sorted after it has been closed.
            if (e.PropertyName == "DetailsPaneVisibility")
            {
                if (DetailsPaneVisibility != Visibility.Visible)
                {
                    sortAllTaskCollections();
                }
            }

            //set SelectedTask to null if it is no longer visible to the user after he chaned the task-section
            else if (e.PropertyName == "AllItemsViewIsVisible" || e.PropertyName == "PendingItemsViewIsVisible" || e.PropertyName == "CompletedItemsViewIsVisible")
            {
                if (!AllItemsViewIsVisible && !PendingItemsViewIsVisible && !CompletedItemsViewIsVisible) return;

                if (!AllItemsViewIsVisible && SelectedTask != null)
                {
                    if ((SelectedTask.Completed && !CompletedItemsViewIsVisible) || (!SelectedTask.Completed && !PendingItemsViewIsVisible))
                    {
                        SelectedTask = null;
                    }
                }
            }
            else if (e.PropertyName == "PendingItems" || e.PropertyName == "CompletedItems")
            {
                PendingItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(updateAllItemsCollection);
                CompletedItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(updateAllItemsCollection);

                updateAllItemsCollection(null, null);
            }
        }

        #endregion



        #region Command Methods

        protected abstract bool addTaskCommandCanExecute(object parameter);

        protected abstract void addTaskCommandExecute(object parameter);


        protected virtual bool deleteTaskCommandCanExecute(object paramter)
        {
            return SelectedTask == null ? false : true;
        }

        protected virtual void deleteTaskCommandExecute(object parameter)
        {
            //TODO: request confirmation
            TaskStore.RemoveTask(SelectedTask.Id);
        }


        protected abstract bool deleteHistoryCommandCanExecute(object parameter);

        protected abstract void deleteHistoryCommandExecute(object parameter);


        protected virtual bool sortAllItemsCommandCanExecute(object parameter)
        {
            return AllItems.Any() ? true : false;
        }

        protected virtual void sortAllItemsCommmandExecute(object parameter)
        {
            sortTaskCollection(parameter, AllItems, ref _allItemsSort, true);
            SortAllItemsButtonText = String.Format("{0} Tasks by {1}", AllItems.Count, AllItemsSort.ToString());
            RaisePropertyChanged("AllItemsSort");
        }


        protected virtual bool sortPendingItemsCommandCanExecute(object parameter)
        {
            return PendingItems.Any() ? true : false;
        }

        protected virtual void sortPendingItemsCommandExecute(object parameter)
        {
            sortTaskCollection(parameter, PendingItems, ref _pendingItemsSort, true);
            SortPendingItemsButtonText = String.Format("{0} Tasks by {1}", PendingItems.Count, PendingItemsSort.ToString());
            RaisePropertyChanged("PendingItemsSort");
        }


        protected virtual bool sortCompletedItemsCommandCanExecute(object parameter)
        {
            return CompletedItems.Any() ? true : false;
        }

        protected virtual void sortCompletedItemsCommandExecute(object parameter)
        {
            sortTaskCollection(parameter, CompletedItems, ref _completedItemsSort, true);
            SortCompletedItemsButtonText = String.Format("{0} Tasks by {1}", CompletedItems.Count, CompletedItemsSort.ToString());
            RaisePropertyChanged("CompletedItemsSort");
        }


        /// <summary>
        /// Executes the ShowDetailsPaneCommand (sets DetailsPaneVisibility to true)
        /// </summary>
        /// <param name="parameter">The command's parameter (will be ignored).</param>
        protected virtual void showDetailsPaneCommandExecute(object parameter)
        {
            DetailsPaneVisibility = Visibility.Visible;
        }

        /// <summary>
        /// Executes the CloseDetailsPaneCommand (sets DetailsPaneVisibility to false)
        /// </summary>
        /// <param name="parameter">The command's parameter (will be ignored).</param>
        protected virtual void closeDetailsPaneCommandExecute(object parameter)
        {
            DetailsPaneVisibility = Visibility.Hidden;
        }
        

        #endregion



        /// <summary>
        /// Determines the next value from the SortBy enum.
        /// </summary>
        /// <param name="sortBy">The current enum value.</param>
        /// <returns>Returns the next value of the SortBy enum based on the specified current value.</returns>
        public static SortBy getNextSortBy(SortBy sortBy)
        {
            switch (sortBy)
            {
                case SortBy.Date:
                    return SortBy.Priority;
                case SortBy.Priority:
                    return SortBy.LastEdited;
                case SortBy.LastEdited:
                    return SortBy.Date;
                default:
                    return SortBy.Date;
            }
        }

        /// <summary>
        /// Determines the previous value from the SortBy enum.
        /// </summary>
        /// <param name="sortBy">The current enum value.</param>
        /// <returns>Returns the previous value of the SortBy enum based on the specified current value.</returns>
        public static SortBy getPreviousSortBy(SortBy sortBy)
        {
            switch (sortBy)
            {
                case SortBy.Date:
                    return SortBy.LastEdited;
                case SortBy.Priority:
                    return SortBy.Date;
                case SortBy.LastEdited:
                    return SortBy.Priority;
                default:
                    return SortBy.Date;
            }
        }


        /// <summary>
        /// Sorts a specified collection of Tasks based on the indicated parameters.
        /// </summary>
        /// <param name="parameter">Can be used to specifiy the ListSortDirection that will be used. Just pass along a string ("descending" or "ascending"). The default is descending.</param>
        /// <param name="collection">The SortableObservableCollection<Task> to be used.</param>
        /// <param name="currentSorting">A reference to the current SortBy value by which the list is sorted.</param>
        /// <param name="changeSorting">Speifies whether the value of SortBy is to be changed (using getNextSortBy()).</param>
        protected virtual void sortTaskCollection(object parameter, SortableObservableCollection<Task> collection, ref SortBy currentSorting, bool changeSorting)
        {
            currentlySorting = true;

            Task selectedTask_cache = SelectedTask;             //save the selected Task as it will be set to null during sorting
            Visibility detailPaneVisibility_cache = DetailsPaneVisibility; //save the Visibility of the DetailsPane as it will be set to Visbile when SeletedTask is set

            ListSortDirection direction = ListSortDirection.Descending;

            if (!String.IsNullOrEmpty((string)parameter))
            {
                switch (((string)parameter).ToLower())
                {
                    case "descending":
                        direction = ListSortDirection.Descending;
                        break;
                    case "ascending":
                        direction = ListSortDirection.Ascending;
                        break;
                }
            }

            if (changeSorting)
            {
                currentSorting = getNextSortBy(currentSorting);
            }


            switch (currentSorting)
            {
                case SortBy.Priority:
                    collection.Sort<int>(x => x.Priority, direction);
                    break;
                case SortBy.Date:
                    collection.Sort<DateTime>(x => x.DueDate, direction);
                    break;
                case SortBy.LastEdited:
                    collection.Sort<DateTime>(x => x.LastEdited, direction);
                    break;
            }


            SelectedTask = selectedTask_cache;                      //reapply values saved before sorting
            DetailsPaneVisibility = detailPaneVisibility_cache;

            currentlySorting = false;
        }

        /// <summary>
        /// Sorts all TaskCollections by their current Sorting (AllItemSort, PendingItemsSort, CompletedItemsSort).
        /// </summary>
        protected virtual void sortAllTaskCollections()
        {
            sortTaskCollection(null, AllItems, ref _allItemsSort, false);
            RaisePropertyChanged("AllItemsSort");
            sortTaskCollection(null, PendingItems, ref _pendingItemsSort, false);
            RaisePropertyChanged("PendingItemsSort");
            sortTaskCollection(null, CompletedItems, ref _completedItemsSort, false);
            RaisePropertyChanged("CompletedItemsSort");
        }

    }

    /// <summary>
    /// A enum that is used to encapsulate by which property a task-list is sorted.
    /// </summary>
    public enum SortBy
    {
        Date = 0,
        Priority,
        LastEdited
    }
}
